package com.example.demo.zwpt;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.Util.HttpUtils;
import com.example.demo.Util.RedisUtils;
import com.example.demo.config.Constant;
import com.example.demo.config.Result;
import com.example.demo.mapper.DataAccessMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @ClassName ZwptJob
 * @Description: 对接政务平台job
 * @Author gss
 * @Date 2021/9/23 10:11
 * @Version V1.0
 **/
@Slf4j
@Component
public class ZwptService {

    /**
     * redis工具类
     *
     */
    @Autowired
    private RedisUtils redisUtils;

    /**
     * 授权id
     *
     */
    @Value("${thirdparty.zwpt.client_id}")
    private String clientId ;

    /**
     * 授权密钥
     *
     */
    @Value("${thirdparty.zwpt.client_secret}")
    private String clientSecret;

    /**
     * 获取token路径
     *
     */
    @Value("${thirdparty.zwpt.tokenUrl}")
    private String tokenUrl ;

    /**
     * 同步全数据用户信息
     *
     */
    @Value("${thirdparty.zwpt.allUserUrl}")
    private String allUserUrl;


    /**
     * 获取标志位url
     *
     */
    @Value("${thirdparty.zwpt.syncFlagUrl}")
    private String syncFlagUrl;


    /**
     * 增量同步数据url
     *
     */
    @Value("${thirdparty.zwpt.incrementUrl}")
    private String incrementUrl;

    @Value("${thirdparty.zwpt.allOuUrl}")
    private String allOuUrl;
    @Autowired
    private DataAccessMapper dataAccessMapper;

    /**
     * 获取标志位
     */
    public Result getAppSyncFlag(){
        //先获取token
        Result oauthToken = this.getOauthToken();
        if(!oauthToken.isSuccess()){
            return oauthToken;
        }
        String token = (String) oauthToken.getResult();
        Map<String, Object> header = this.getMapBuilder().put("Authorization", "Bearer " + token).map();
        String response = HttpUtils.httpPost(syncFlagUrl,header,null);
        if(StringUtils.isBlank(response)){
            log.info("调用最新变更标志位接口，返回报文为空");
            return Result.error("调用最新变更标志位接口，返回报文为空");
        }
        //解析
        try{
            JSONObject responseObj = JSON.parseObject(response);
            String status = responseObj.getString("status");
            if("1".equals(status)){
                //获取标志位
                String result = responseObj.getString("result");
                return Result.OK(result);
            }else{
                return Result.error(responseObj.containsKey("error")?responseObj.getString("error"):responseObj.getString("description"));
            }
        }catch (Exception e){
            log.error("调用最新变更标志位接口异常：",e);
            return Result.error(e.getMessage());
        }

    }

    /**
     * 查询增量数据调用
     */
    public Result queryAllIncrement(){
        Object syncFlag = redisUtils.get(Constant.SYNC_FLAG);
        Result appSyncFlagResult = this.getAppSyncFlag();
        if(!appSyncFlagResult.isSuccess()){
            return appSyncFlagResult;
        }
        //获取接口值
        String interfaceSyncFlag = (String)appSyncFlagResult.getResult();
        if(interfaceSyncFlag.equals(syncFlag)){
            return Result.OK("数据未发生变化");
        }
        //调用增量数据同步
        Result oauthToken = this.getOauthToken();
        if(!oauthToken.isSuccess()){
            return oauthToken;
        }
        String token = (String) oauthToken.getResult();
        Map<String, Object> header = this.getMapBuilder().put("Authorization", "Bearer " + token).map();
        String responseStr = HttpUtils.httpPost(incrementUrl, header, null);
        if(StringUtils.isBlank(responseStr)){
            log.info("调用增量同步数据接口，返回报文为空");
            return Result.error("调用增量同步数据接口，返回报文为空");
        }
        try{
            JSONObject responseObj = JSON.parseObject(responseStr);
            String status = responseObj.getString("status");
            if("1".equals(status)){
                //获取标志位
                JSONObject result = responseObj.getJSONObject("result");
                //获取用户增量信息
                JSONObject frameUser = result.getJSONObject("FrameUser");
                this.parseFrameUser(frameUser);
                //获取用户扩展增量信息
                JSONObject frameUserExtendInfo = result.getJSONObject("FrameUserExtendInfo");
                this.parseFrameUserExtendInfo(frameUserExtendInfo);
                //获取部门增量信息
                JSONObject frameOu = result.getJSONObject("FrameOu");
                this.parseFrameOu(frameOu);
                //获取部门扩展增量信息
                JSONObject frameOuExtendInfo = result.getJSONObject("FrameOuExtendInfo");
                this.parseFrameOuExtendInfo(frameOuExtendInfo);
                //此处更新标志位
                redisUtils.set(Constant.SYNC_FLAG,interfaceSyncFlag);
                return Result.OK(result);
            }else{
                return Result.error(responseObj.containsKey("error")?responseObj.getString("error"):responseObj.getString("description"));
            }
        }catch (Exception e){
           log.error("调用增量同步数据接口解析返回报文异常：",e);
           return Result.error(e.getMessage());
        }
    }

    /**
     * 解析增量用户数据并保存
     */
    public void parseFrameUser(JSONObject frameUser){
        JSONArray insert = frameUser.getJSONArray("insert");
        if(!CollectionUtil.isEmpty(insert)){
            log.info("增量用户数据进行新增操作-------开始");
            //由于json字段的不一致，暂时先单个插入，看后续对方是否调整
            List<Map<String, Object>> collect = insert.stream().map(e -> {
                JSONObject object =(JSONObject)e;
                object.remove("userextendinfo");
                return object;
            }).collect(Collectors.toList());
            //this.batchInsert("frame_user",collect);
            collect.stream().forEach(e->{
                dataAccessMapper.insertData("frame_user",e.keySet(),e);
            });
            log.info("增量用户数据进行新增操作-------结束");
        }
        JSONArray update = frameUser.getJSONArray("update");
        if(!CollectionUtil.isEmpty(update)){
            log.info("增量用户数据进行更新操作-------开始");
            update.stream().forEach(e->{
                JSONObject object = (JSONObject) e;
                object.remove("userextendinfo");
                dataAccessMapper.updateDataByKey("frame_user","userguid",object.getString("userguid"),object);
            });
            log.info("增量用户数据进行更新操作-------结束");
        }
        JSONArray delete = frameUser.getJSONArray("delete");
        if(!CollectionUtil.isEmpty(delete)){
            log.info("增量用户数据进行删除操作-------开始");
            List<String> userguidList = delete.stream().map(e -> {
                JSONObject object = (JSONObject) e;
                return object.getString("userguid");
            }).collect(Collectors.toList());
            this.batchDelete("frame_user","userguid",userguidList);
            log.info("增量用户数据进行删除操作-------结束");
        }
    }
    /**
     * 解析增量部门数据并保存
     */
    public void parseFrameOu(JSONObject frameOu){
        JSONArray insert = frameOu.getJSONArray("insert");
        if(!CollectionUtil.isEmpty(insert)){
            log.info("增量部门数据进行新增操作-------开始");
            //由于json字段的不一致，暂时先单个插入，看后续对方是否调整
            List<Map<String, Object>> collect = insert.stream().map(e -> {
                JSONObject object =(JSONObject)e;
                object.remove("frame_ou_extendinfo");
                return object;
            }).collect(Collectors.toList());
            collect.stream().forEach(e->{
                dataAccessMapper.insertData("frame_ou",e.keySet(),e);
            });
            log.info("增量部门数据进行新增操作-------结束");
        }
        JSONArray update = frameOu.getJSONArray("update");
        if(!CollectionUtil.isEmpty(update)){
            log.info("增量部门数据进行更新操作-------开始");
            update.stream().forEach(e->{
                JSONObject object = (JSONObject) e;
                object.remove("frame_ou_extendinfo");
                dataAccessMapper.updateDataByKey("frame_ou","OUGUID",object.getString("OUGUID"),object);
            });
            log.info("增量部门数据进行更新操作-------结束");
        }
        JSONArray delete = frameOu.getJSONArray("delete");
        if(!CollectionUtil.isEmpty(delete)){
            log.info("增量部门数据进行删除操作-------开始");
            List<String> ouguidList = delete.stream().map(e -> {
                JSONObject object = (JSONObject) e;
                return object.getString("OUGUID");
            }).collect(Collectors.toList());
            this.batchDelete("frame_ou","OUGUID",ouguidList);
            log.info("增量部门数据进行删除操作-------结束");
        }
    }

    /**
     * 解析增量用户扩展数据并保存
     */
    private void parseFrameUserExtendInfo(JSONObject frameUserExtendInfo){
        JSONArray insert = frameUserExtendInfo.getJSONArray("insert");
        if(!CollectionUtil.isEmpty(insert)){
            log.info("增量用户扩展数据进行新增操作-------开始");
            List<Map<String, Object>> collect = insert.stream().map(e -> {
                return (Map<String, Object>) e;
            }).collect(Collectors.toList());
            //this.batchInsert("frame_user_extendinfo",collect);
            collect.stream().forEach(e->{
                dataAccessMapper.insertData("frame_user_extendinfo",e.keySet(),e);
            });
            log.info("增量用户扩展数据进行新增操作-------结束");
        }
        JSONArray update = frameUserExtendInfo.getJSONArray("update");
        if(!CollectionUtil.isEmpty(update)){
            log.info("增量用户扩展数据进行更新操作-------开始");
            update.stream().forEach(e->{
                JSONObject object = (JSONObject) e;
                dataAccessMapper.updateDataByKey("frame_user_extendinfo","userguid",object.getString("userguid"),object);
            });
            log.info("增量用户扩展数据进行更新操作-------结束");
        }
        JSONArray delete = frameUserExtendInfo.getJSONArray("delete");
        if(!CollectionUtil.isEmpty(delete)){
            log.info("增量用户扩展数据进行删除操作-------开始");
            List<String> userguidList = delete.stream().map(e -> {
                JSONObject object = (JSONObject) e;
                return object.getString("userguid");
        }).collect(Collectors.toList());
            this.batchDelete("frame_user_extendinfo","userguid",userguidList);
            log.info("增量用户扩展数据进行删除操作-------结束");
        }
    }

    /**
     * 解析增量部门扩展数据并保存
     */
    private void parseFrameOuExtendInfo(JSONObject frameOuExtendInfo){
        JSONArray insert = frameOuExtendInfo.getJSONArray("insert");
        if(!CollectionUtil.isEmpty(insert)){
            log.info("增量部门扩展数据进行新增操作-------开始");
            List<Map<String, Object>> collect = insert.stream().map(e -> {
                return (Map<String, Object>) e;
            }).collect(Collectors.toList());
            collect.stream().forEach(e->{
                dataAccessMapper.insertData("frame_ou_extendinfo",e.keySet(),e);
            });
            log.info("增量部门扩展数据进行新增操作-------结束");
        }
        JSONArray update = frameOuExtendInfo.getJSONArray("update");
        if(!CollectionUtil.isEmpty(update)){
            log.info("增量部门扩展数据进行更新操作-------开始");
            update.stream().forEach(e->{
                JSONObject object = (JSONObject) e;
                dataAccessMapper.updateDataByKey("frame_ou_extendinfo","OUGUID",object.getString("OUGUID"),object);
            });
            log.info("增量部门扩展数据进行更新操作-------结束");
        }
        JSONArray delete = frameOuExtendInfo.getJSONArray("delete");
        if(!CollectionUtil.isEmpty(delete)){
            log.info("增量部门扩展数据进行删除操作-------开始");
            List<String> ouguidList = delete.stream().map(e -> {
                JSONObject object = (JSONObject) e;
                return object.getString("OUGUID");
            }).collect(Collectors.toList());
            this.batchDelete("frame_ou_extendinfo","OUGUID",ouguidList);
            log.info("增量部门扩展数据进行删除操作-------结束");
        }
    }

    /**
     * 全量数据同步
     */
    public Result queryAllUser(){
        //先获取token
        Result oauthToken = this.getOauthToken();
        if(!oauthToken.isSuccess()){
            return oauthToken;
        }
        String token = (String) oauthToken.getResult();
        Map<String, Object> header = this.getMapBuilder().put("Authorization", "Bearer " + token).map();
        String responseStr = HttpUtils.httpPost(allUserUrl, header, null);
        JSONObject responseObj = JSON.parseObject(responseStr);
        //待插入的数据
        List<Map<String,Object>> userList = new ArrayList<>();
        List<Map<String,Object>> userExtList = new ArrayList<>();
        try{
            String status = responseObj.getString("status");
            if("1".equals(status)){
                //获取数据值
                JSONArray result = responseObj.getJSONArray("result");
                JSONObject item = null;
                JSONObject itemExt = null;
                if(!CollectionUtil.isEmpty(result)){
                    for(int i=0;i<result.size();i++){
                        item = result.getJSONObject(i);
                        itemExt = item.getJSONObject("userextendinfo");
                        userExtList.add(itemExt);
                        item.remove("userextendinfo");
                        userList.add(item);
                    }
                }

            }else{
                return Result.error(responseObj.containsKey("error")?responseObj.getString("error"):responseObj.getString("description"));
            }
        }catch (Exception e){
            log.error("全量同步用户数据信息异常：",e);
            return Result.error(e.getMessage());
        }
        // 需要插入数据库，整体可能还需要调整，后续调整
        if(!CollectionUtil.isEmpty(userList)) {
            this.batchInsert("frame_user", userList);
        }
        if(!CollectionUtil.isEmpty(userExtList)){
            this.batchInsert("frame_user_extendinfo", userExtList);
        }
        return Result.OK("全量同步用户数据成功");
    }

    /**
     * 全量部门数据同步
     */
    public Result getAllOu(){
        //先获取token
        Result oauthToken = this.getOauthToken();
        if(!oauthToken.isSuccess()){
            return oauthToken;
        }
        String token = (String) oauthToken.getResult();
        Map<String, Object> header = this.getMapBuilder().put("Authorization", "Bearer " + token).map();
        String responseStr = HttpUtils.httpPost(allOuUrl, header, null);
        JSONObject responeJSONObject = JSON.parseObject(responseStr, JSONObject.class);
//        JSONArray resultArr = responeJSONObject.getJSONArray("result");
//        List<Map<String,Object>> ouArr = new ArrayList<>();
//        List<Map<String,Object>> ouExtendArr = new ArrayList<>();
//        JSONArray ouArr = new JSONArray();
//        JSONArray ouExtendArr = new JSONArray();
        try{
            String status = responeJSONObject.getString("status");
            if("1".equals(status)){
                //获取数据值
                JSONArray result = responeJSONObject.getJSONArray("result");
                JSONObject item = null;
                JSONObject itemExt = null;
                if(!CollectionUtil.isEmpty(result)){
                    for(int i=0;i<result.size();i++){
                        item = result.getJSONObject(i);
                        itemExt = item.getJSONObject("extendinfo");
//                        ouExtendArr.add(itemExt);
                        item.remove("extendinfo");
                        try{
                            dataAccessMapper.insertData("frame_ou_extendinfo", itemExt.keySet(), itemExt);
                            dataAccessMapper.insertData("frame_ou", item.keySet(), item);
                        }catch (Exception e){
                            log.error("政务部门数据：{},拓展表数据：{}",item,itemExt);
                            log.error("插入政务部门数据报错：{}",e);
                            continue;
                        }
                    }
                }
            }else{
                return Result.error(responeJSONObject.getString("error"));
            }
        }catch (Exception e){
            log.error("全量同步部门数据信息异常：",e);
            return Result.error(e.getMessage());
        }

        return Result.OK(responseStr);
    }


    /**
     * @method getOauthToken
     * @Author gss
     * @Version  1.0
     * @Description 获取token
      * @param
     * @Return com.example.demo.config.Result
     * @Date 2021/9/23 14:41
     */
    public  Result getOauthToken(){
        //先从redis读取，没有在调用接口实时获取
        Object cacheToken = redisUtils.get(Constant.TOKEN_PREFIX);
        if(cacheToken!=null){
            return Result.OK(cacheToken);
        }
        return this.queryOauthTokenByOa(clientId,clientSecret,tokenUrl);
    }

    /**
     * @method queryOauthTokenByOa
     * @Author gss
     * @Version  1.0
     * @Description 调用接口获取token
      * @param clientId 授权id
     * @param clientSecret 授权密钥
     * @param tokenUrl 接口路径
     * @Return java.lang.String
     * @Date 2021/9/23 13:47
     */
    public  Result queryOauthTokenByOa(String clientId, String clientSecret, String tokenUrl){
        //封装参数
        MapBuilder<String, String> builder = MapUtil.builder();
        Map<String, String> params = builder.put("client_id", clientId).put("client_secret", clientSecret).put("grant_type", "client_credentials").map();

        String response = HttpUtils.httpsPostForm(tokenUrl, null, params);
        if(StringUtils.isBlank(response)){
            log.info("调用接口返回报文为空");
            return Result.error("调用接口返回报文为空");
        }
        //解析报文
        JSONObject object = JSON.parseObject(response);
        try{
            JSONObject codeObj = object.getJSONObject("status");
            String code = codeObj.getString("code");
            if(code.equals("1")){
                JSONObject custom = object.getJSONObject("custom");
                String token = custom.getString("access_token");
                int expire = custom.getInteger("expires_in");
                //设置进redis
                redisUtils.set(Constant.TOKEN_PREFIX,token,expire-20);
                return Result.OK(token);
            }else{
                //失败
                String text = codeObj.getString("text");
                log.info("调用接口失败：{}",text);
                return Result.error(text);
            }
        }catch (Exception e){
            log.error("解析报文异常：",e);
            return Result.error(e.getMessage());
        }
    }


    private MapBuilder<String,Object> getMapBuilder(){
        return MapUtil.builder();
    }


    /**
     * @method batchInsert
     * @Author gss
     * @Version  1.0
     * @Description 分批次批量插入
     * @param tableName 表名
     * @param dataList 待插入数据
     * @Return void
     * @Date 2021/9/23 17:26
     */
    private void batchInsert(String tableName,List<Map<String,Object>> dataList){
        log.info("进行数据库插入----------开始");
        //分批推送
        int selectSize = 500;
        //计算切分次数
        int limitCount = (dataList.size()+selectSize-1)/selectSize;
        //分成多少次请求
        Stream.iterate(0, n->n+1).limit(limitCount).forEach(e->{
            //拿到这个参数的流的（a * selectSize）后面的数据.limit（selectSize）->后面数据的500条
            List<Map<String,Object>> collect = dataList.stream().skip(e * selectSize).limit(selectSize).collect(Collectors.toList());
            //插入数据库
            dataAccessMapper.batchInsertData(tableName, collect.get(0).keySet(), collect);
        });
        log.info("进行数据库插入----------结束");
    }

    /**
     * 删除增量数据同步
     */
    private void batchDelete(String tableName,String col,List<String> dataList){
        log.info("进行数据库删除----------开始");
        //分批推送
        int selectSize = 500;
        //计算切分次数
        int limitCount = (dataList.size()+selectSize-1)/selectSize;
        //分成多少次请求
        Stream.iterate(0, n->n+1).limit(limitCount).forEach(e->{
            //拿到这个参数的流的（a * selectSize）后面的数据.limit（selectSize）->后面数据的500条
            List<String> collect = dataList.stream().skip(e * selectSize).limit(selectSize).collect(Collectors.toList());
            //插入数据库
            dataAccessMapper.batchDeleteData(tableName, col, collect);
        });
        log.info("进行数据库删除----------结束");
    }

    public static void main(String [] args){
        ZwptService zwptService = new ZwptService();
        zwptService.queryAllUser();
    }

}
